home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Misc / a2 / Source / disk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-21  |  7.5 KB  |  353 lines

  1. /*
  2.  *  a2, an Apple II emulator in C
  3.  *  (c) Copyright 1990 by Rich Skrenta
  4.  *
  5.  *  Command line interface written by Tom Markson
  6.  *
  7.  *  Distribution agreement:
  8.  *
  9.  *    You may freely copy or redistribute this software, so long
  10.  *    as there is no profit made from its use, sale, trade or
  11.  *    reproduction.  You may not change this copyright notice,
  12.  *    and it must be included prominently in any copy made.
  13.  *
  14.  *  Send emulator related mail to:  skrenta@blekko.commodore.com
  15.  *                    skrenta@blekko.uucp
  16.  */
  17.  
  18.  
  19. #import    <stdio.h>
  20. #import    <libc.h>
  21. #import    "a2.h"
  22.  
  23.  
  24. #define        GAP    0x7F;        /* data gap byte */
  25.  
  26.  
  27. /*
  28.  *  4 by 4 nibble encoding macros
  29.  */
  30.  
  31. #define        nib1(a)    (((a) >> 1) | 0xAA)
  32. #define        nib2(a)    ((a) | 0xAA)
  33. #define        denib(a,b)    (((((a) & 0x55) << 1) & 0xFF) | ((b) & 0x55))
  34.  
  35.  
  36. int cur_track[2] = {0, 0};
  37. int sect_pos[2];        /* current sector within track */
  38.  
  39. extern unsigned char tab1[];    /* For nibblizing.  At end of this file */
  40. extern unsigned char tab2[];    /* Disk byte translation table. */
  41. extern unsigned char phys[];    /* DOS 3.3 to physical sector mapping */
  42.  
  43. unsigned char sect_buf[2][1024];
  44. unsigned char *sectp = NULL;
  45. unsigned char *sect_point[2] = {NULL, NULL};
  46. unsigned char write_reg;    /* write data register */
  47. int write_mode = FALSE;
  48.  
  49.  
  50.  
  51. /*
  52.  *  Determine what track the disk head is over by watching toggles to
  53.  *  the four stepper motor magnets.
  54.  */
  55.  
  56. void step_motor(unsigned short a)
  57. {
  58. static    int mag[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}},
  59.     pmag[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}},    /* previous */
  60.     ppmag[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}},    /* previous previous */
  61.     pnum[2] = {0, 0},
  62.     ppnum[2] = {0, 0},
  63.     track_pos[2] = {0, 0};
  64.  
  65. static int prev_track[2] = {0, 0};
  66. int magnet_number;
  67.  
  68.     a &= 7;
  69.     magnet_number = a >> 1;
  70.  
  71.     ppmag[drive][ppnum[drive]] = pmag[drive][ppnum[drive]];
  72.     ppnum[drive] = pnum[drive];
  73.  
  74.     pmag[drive][pnum[drive]] = mag[drive][pnum[drive]];
  75.     pnum[drive] = magnet_number;
  76.  
  77.     if ((a & 1) == 0)
  78.         mag[drive][magnet_number] = FALSE;
  79.     else {
  80.         if (ppmag[drive][(magnet_number + 1) & 3]) {
  81.             track_pos[drive]--;
  82.             if (track_pos[drive] < 0) {
  83.                 track_pos[drive] = 0;
  84.                 if (drive)
  85.                     info("recal d2");
  86.                 else
  87.                     info("recal");
  88.             }
  89.         }
  90.  
  91.         if (ppmag[drive][(magnet_number - 1) & 3]) {
  92.             track_pos[drive]++;
  93.             if (track_pos[drive] > 140)
  94.                 track_pos[drive] = 140;
  95.  
  96.         }
  97.         mag[drive][magnet_number] = TRUE;
  98.     }
  99.  
  100.     cur_track[drive] = (track_pos[drive] + 1) / 2;
  101.     if (cur_track[drive] != prev_track[drive]) {
  102. #if 0
  103.         sprintf(s, "step to %d%s", cur_track[drive],
  104.                         drive ? " d2" : "");
  105.         info(s);
  106. #endif
  107.         sectp[drive] = 0;  /* recompute sector if head moves */
  108.         sect_pos[drive] = 0;
  109.         prev_track[drive] = cur_track[drive];
  110.     }
  111. }
  112.  
  113.  
  114. /*
  115.  *  Take a normal 256 byte sector and nibblize it into 342 bytes
  116.  *  Checksum it with itself; this yields one more byte.
  117.  *  Translate the resulting 343 bytes into "disk bytes".
  118.  *  Insert them into the sector buffer.
  119.  *
  120.  *  See a reference such as _Beneath Apple Prodos_ for an explanation
  121.  *  of why & how this is done.
  122.  */
  123.  
  124. void read_disk(int track, int sector, unsigned char *buf)
  125. {
  126.   long block;
  127.  
  128.   block = track * 16 + sector;
  129.  
  130.   lseek(disk[drive], block * 256, 0);
  131.   if (read(disk[drive], buf, 256) != 256)
  132.     perror("bad read");
  133. }
  134.  
  135.  
  136. void write_disk(int track, int sector, unsigned char *buf)
  137. {
  138.   long block;
  139.  
  140.   block = track * 16 + sector;
  141.  
  142.   lseek(disk[drive], block * 256, 0);
  143.   if (write(disk[drive], buf, 256) != 256)
  144.     perror("bad write");
  145. }
  146.  
  147. void encode_data(int track, int sector)
  148. {
  149. unsigned char buf[344];
  150. unsigned char *one;
  151. unsigned char *bump;
  152. unsigned char *two;
  153. unsigned char *three;
  154. unsigned char *dest;
  155. int i;
  156.  
  157.     read_disk(track, sector, &buf[86]);
  158.     buf[342] = 0;
  159.     buf[343] = 0;
  160.  
  161.     dest = buf;
  162.     one = &buf[86];
  163.     two = &buf[86 + 0x56];
  164.     bump = two;
  165.     three = &buf[86 + 0xAC];
  166.  
  167.     do {
  168.         i = (*one++ & 0x03) |
  169.             ((*two++ & 0x03) << 2) | ((*three++ & 0x03) << 4);
  170.  
  171.         *dest++ = tab1[i];
  172.     } while (one != bump);
  173.  
  174.     sectp[0] = buf[0];
  175.     for (i = 1; i <= 342; i++)
  176.         sectp[i] = buf[i - 1] ^ buf[i];
  177.  
  178.     for (i = 0; i <= 342; i++)
  179.         sectp[i] = tab2[ sectp[i] >> 2 ];
  180.  
  181.     sectp = §p[343];
  182. }
  183.  
  184. void setup_sector(int track, int sector)
  185. {
  186. int checksum;
  187. int physical_sector;
  188. char s[50];
  189. int i;
  190.  
  191.     physical_sector = phys[sector];
  192.  
  193.     sprintf(s, "raw t=%d s=%d%s", track, sector, drive ? " d2" : "");
  194.     info(s);
  195.  
  196.     sectp = sect_buf[drive];
  197.  
  198.     for (i = 0; i < 16; i++)
  199.         *sectp++ = GAP;
  200.  
  201.     *sectp++ = 0xD5;            /* address header */
  202.     *sectp++ = 0xAA;
  203.     *sectp++ = 0x96;
  204.  
  205.     *sectp++ = 0xFF;            /* disk volume 254 */
  206.     *sectp++ = 0xFE;
  207.  
  208.     *sectp++ = nib1(track);
  209.     *sectp++ = nib2(track);
  210.  
  211.     *sectp++ = nib1(physical_sector);
  212.     *sectp++ = nib2(physical_sector);
  213.  
  214.     checksum = 254 ^ track ^ physical_sector;
  215.     *sectp++ = nib1(checksum);
  216.     *sectp++ = nib2(checksum);
  217.  
  218.     *sectp++ = 0xDE;            /* address trailer */
  219.     *sectp++ = 0xAA;
  220.  
  221.     for (i = 0; i < 8; i++)
  222.         *sectp++ = GAP;
  223.  
  224.     *sectp++ = 0xD5;            /* data header */
  225.     *sectp++ = 0xAA;
  226.     *sectp++ = 0xAD;
  227.  
  228.     encode_data(track, sector);        /* nibblized data */
  229.  
  230.     *sectp++ = 0xDE;            /* data trailer */
  231.     *sectp++ = 0xAA;
  232.     *sectp++ = 0xEB;
  233.  
  234.     *sectp = '\0';                /* ending mark for our use */
  235.     sectp = sect_buf[drive];        /* start reading at beginning */
  236. }
  237.  
  238.  
  239. void raw_disk_write(void)
  240. {
  241.   printf("raw write %.2X\n", write_reg);
  242. }
  243.  
  244.  
  245. /*
  246.  *  Helps with the bit fiddling necessary to extract the bottom
  247.  *  two bits during the 256 - 342 byte nibblize.
  248.  */
  249.  
  250. unsigned char tab1[] = {
  251.     0x00, 0x08, 0x04, 0x0C, 0x20, 0x28, 0x24, 0x2C,
  252.     0x10, 0x18, 0x14, 0x1C, 0x30, 0x38, 0x34, 0x3C,
  253.     0x80, 0x88, 0x84, 0x8C, 0xA0, 0xA8, 0xA4, 0xAC,
  254.     0x90, 0x98, 0x94, 0x9C, 0xB0, 0xB8, 0xB4, 0xBC,
  255.     0x40, 0x48, 0x44, 0x4C, 0x60, 0x68, 0x64, 0x6C,
  256.     0x50, 0x58, 0x54, 0x5C, 0x70, 0x78, 0x74, 0x7C,
  257.     0xC0, 0xC8, 0xC4, 0xCC, 0xE0, 0xE8, 0xE4, 0xEC,
  258.     0xD0, 0xD8, 0xD4, 0xDC, 0xF0, 0xF8, 0xF4, 0xFC,
  259. };
  260.  
  261.  
  262. /*
  263.  *  Translates to "disk bytes"
  264.  */
  265.  
  266. unsigned char tab2[] = {
  267.     0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, 
  268.     0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3, 
  269.     0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, 
  270.     0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3, 
  271.     0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 
  272.     0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, 
  273.     0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 
  274.     0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 
  275. };
  276.  
  277.  
  278. /*
  279.  *  Dos 3.3 to physical sector conversion
  280.  */
  281.  
  282. unsigned char phys[] = {
  283.     0x00, 0x0D, 0x0B, 0x09, 0x07, 0x05, 0x03, 0x01,
  284.     0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x0F,
  285. };
  286.  
  287. unsigned char disk_ref(unsigned short a, unsigned char n)
  288. {
  289.     switch (a) {
  290.     case 0xC0E0:    /* Phase 0 off */
  291.     case 0xC0E1:    /* Phase 0 on */
  292.     case 0xC0E2:    /* Phase 1 off */
  293.     case 0xC0E3:    /* Phase 1 on */
  294.     case 0xC0E4:    /* Phase 2 off */
  295.     case 0xC0E5:    /* Phase 2 on */
  296.     case 0xC0E6:    /* Phase 3 off */
  297.     case 0xC0E7:    /* Phase 3 on */
  298.         step_motor(a);
  299.         break;
  300.  
  301.     case 0xC0E8:    /* Drive off */
  302.         break;
  303.  
  304.     case 0xC0E9:    /* Drive on */
  305.         break;
  306.  
  307.     case 0xC0EA:    /* Select drive 1 */
  308.         sect_point[drive] = sectp;
  309.         drive = 0;
  310.         sectp = sect_point[0];
  311.         break;
  312.  
  313.     case 0xC0EB:    /* Select drive 2 */
  314.         sect_point[drive] = sectp;
  315.         drive = 1;
  316.         sectp = sect_point[1];
  317.         break;
  318.  
  319.     case 0xC0EC:    /* Shift data register */
  320.         if (disk[drive] < 0)
  321.             return(0xFF);
  322.  
  323.         if (write_mode) {
  324.             raw_disk_write();
  325.             return(0);
  326.         }
  327.  
  328.         if (sectp == NULL || *sectp == '\0') {
  329.             sect_pos[drive]--;
  330.             if (sect_pos[drive] < 0)
  331.                 sect_pos[drive] = 15;
  332.             setup_sector(cur_track[drive], sect_pos[drive]);
  333.         }
  334.  
  335.         return(*sectp++);
  336.  
  337.     case 0xC0ED:    /* Load data register */
  338.         write_reg = n;
  339.         break;
  340.  
  341.     case 0xC0EE:    /* Read mode */
  342.         write_mode = FALSE;
  343.         return(write_prot[drive] ? 0xFF : 0);
  344.         break;
  345.  
  346.     case 0xC0EF:    /* Write mode */
  347.         write_mode = TRUE;
  348.         break;
  349.     }
  350.  
  351.     return(0);
  352. }
  353.